package com.starsoft.quant.web;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import com.starsoft.frame.util.MapUtil;
import com.starsoft.quant.analysis.VolatilityService;
import com.starsoft.quant.bean.QuantAcount;
import com.starsoft.quant.bean.QuantDetail;
import com.starsoft.quant.bean.QuantModel;
import com.starsoft.quant.bean.QuantModelColumn;
import com.starsoft.quant.bean.QuantModelParam;
import com.starsoft.quant.service.QuantModelService;
import com.starsoft.quant.service.QuantReportService;
import com.starsoft.smdc.bean.SmdcSecurity;
import com.starsoft.smdc.service.SecurityService;

@RestController
@RequestMapping("/quant/report")
public class  BackReportController extends QuantReportControllerBase{
	
	@Autowired
	QuantReportService quantReportService;
	
	@Autowired
	SecurityService securityService;
	
	@Autowired
	QuantModelService quantModelService;

	@Autowired
	VolatilityService volatilityService;
	
	@RequestMapping("/backreportpage")
	public ModelAndView getReportPage(HttpServletRequest request, ModelAndView model) {
		List<String> message = new ArrayList<String>();
		List<QuantAcount> acounts = getQuantAcount(request, message);
		if (acounts.isEmpty()) {
			model.addObject("acountId", -1);
			model.setViewName("backreport");
			return model;
		}
		QuantAcount quantAcount = acounts.get(0);
		if (quantAcount != null) {
			List<QuantModelParam> params = modelParamService.getModelParams(quantAcount.getModelCode());
			model.addObject("params", params);
	
			QuantModel quantModel = quantAcountService.getModel(quantAcount.getAcountId());
			List<QuantModelColumn> quantModelCols = quantModelService.getOrderedNumberColumns(quantModel);
			model.addObject("quantModelCols", quantModelCols);
		}
		model.addObject("acountId", quantAcount.getAcountId());
		model.setViewName("backreport");
		return model;
	}
	
	@RequestMapping("/backreport.json")
	public Map<String, Object> getBackReport(ServletRequest request) throws Exception {
		Map<String, Object> model = new HashMap<>();
		List<String> message = new ArrayList<String>();
		List<QuantAcount> acounts = getQuantAcount(request, message);
		QuantAcount quantAcount = acounts.get(0);
		
		Date reportDate = getReportDate(request);
		Date beginDate = null;
		String columnSelect = getQuantDetailColumn(request);
		boolean isRefresh = "true".equalsIgnoreCase(request.getParameter("isRefresh"));
		if (quantAcount.getEndDate() != null && reportDate.after(quantAcount.getEndDate())) {
			reportDate = quantAcount.getEndDate();
		}
		if (beginDate == null) {
			beginDate = quantAcount.getStartDate();
		}
		if (isRefresh) {
			reportService.updateAnalysis(quantAcount.getAcountId(), reportDate);
		}

		model.put("modelconfig", loadConfig(quantAcount, reportDate));
		model.put("risk", loadRisk(quantAcount.getAcountId(), reportDate));
		model.put("profit", loadProfit(quantAcount.getAcountId(), beginDate, reportDate));
		model.put("quantDetail", loadQuantDetail(quantAcount.getAcountId(), beginDate, reportDate, columnSelect));
		return model;
	}
	
	@ResponseBody
	@RequestMapping(value = "/profit")
	public Map<String, Object> getProfit(ServletRequest request) throws Exception {
		List<String> message = new ArrayList<String>();
		List<QuantAcount> acounts = getQuantAcount(request, message);
		QuantAcount quantAcount = acounts.get(0);
		
		Date reportDate = getReportDate(request);
		Date beginDate = getBeginDate(request, reportDate, acounts);
		if (quantAcount.getEndDate() != null && reportDate.after(quantAcount.getEndDate())) {
			reportDate = quantAcount.getEndDate();
		}
		if (beginDate == null || beginDate.before(quantAcount.getStartDate())) {
			beginDate = quantAcount.getStartDate();
		}
		
		Map<String, Object> model = new HashMap<>();
		model.put("profit", loadProfit(quantAcount.getAcountId(), beginDate, reportDate));
		return model;
	}
	
	@RequestMapping(value = "/quantdetail")
	public Map<String, Object> getQuantDetail(ServletRequest request) throws Exception {
		List<String> message = new ArrayList<String>();
		List<QuantAcount> acounts = getQuantAcount(request, message);
		QuantAcount quantAcount = acounts.get(0);
		
		Date reportDate = getReportDate(request);
		Date beginDate = null;
		String columnSelect = getQuantDetailColumn(request);
		if (quantAcount.getEndDate() != null && reportDate.after(quantAcount.getEndDate())) {
			reportDate = quantAcount.getEndDate();
		}
		if (beginDate == null) {
			beginDate = quantAcount.getStartDate();
		}
		
		Map<String, Object> model = new HashMap<>();
		model.put("quantDetail", loadQuantDetail(quantAcount.getAcountId(), beginDate, reportDate, columnSelect));
		return model;
	}
	
	private String getQuantDetailColumn(ServletRequest request){
		String colName = request.getParameter("quantDetailColumn");
		if(colName==null){
			colName = "rating";
		}
		return colName;
	}
	
	private Map<String, Object> loadQuantDetail(Integer acountId, Date beginDate, Date reportDate, String columnSelect){
		List<QuantDetail> details = quantReportService.getDetailsBetween(acountId, beginDate, reportDate);
		Set<Date> timeLine = new LinkedHashSet<Date>();
		Set<String> secList = new HashSet<String>();
		Map<String, QuantDetail> detailMap = new HashMap<String, QuantDetail>();
		for(QuantDetail qDetail : details){
			String key = qDetail.getId().getDate()+qDetail.getId().getSecId();
			timeLine.add(qDetail.getId().getDate());
			secList.add(qDetail.getId().getSecId());
			detailMap.put(key, qDetail);
		}
		
		Map<String, List<Double>> lineDataMap = new HashMap<String, List<Double>>();
		for(String secId : secList){
			List<Double> lineData = new ArrayList<Double>();
			for(Date date : timeLine){
				String key = date + secId;
				if(detailMap.containsKey(key)){
					Double value = getValue(detailMap.get(key), columnSelect);
					lineData.add(value);
				} else {
					lineData.add(null);
				}
			}
			SmdcSecurity security = securityService.get(secId);
			String secName = null;
			if(security!=null){
				secName = securityService.get(secId).getSecName();
			} else {
				secName = secId+".del";
			}
			
			if(columnSelect.equals("price")) lineData = volatilityService.rebase(lineData);
			lineDataMap.put(secName, lineData);
		}
		
		Map<String, Object> result = new HashMap<>();
		result.put("timeLine", timeLine);
		result.put("lineData", lineDataMap);
		return result;
	}
	
	private Double getValue(QuantDetail detail, String column){
		Double value = null;
		Object ob = MapUtil.getValue(detail, column);
		if(ob == null){
			return null;
		}
		if(ob instanceof Double){
			value = (Double) ob;
		} else if (ob instanceof String) {
			try {
				value = Double.parseDouble((String) ob);
			} catch (Exception e) {
				return null;
			}
		}
		if(Math.abs(value)>1)
		return Math.rint(value*100)/100;
		else return Math.rint(value*10000)/10000;
	}

}